package top.broncho.lottery.util

import android.content.Context
import com.baidu.ocr.sdk.OCR
import com.baidu.ocr.sdk.OnResultListener
import com.baidu.ocr.sdk.exception.OCRError
import com.baidu.ocr.sdk.model.AccessToken
import com.baidu.ocr.sdk.model.GeneralParams
import com.baidu.ocr.sdk.model.GeneralResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.anko.AnkoLogger
import org.jetbrains.anko.info
import org.jetbrains.anko.warn
import top.broncho.lottery.model.ocr.OcrResult
import top.broncho.lottery.ui.main.MainViewModule
import java.io.File
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

private const val OCR_LICENSE = "aip.license"

const val FILE_NAME = "lottery.jpg"

private const val DATE_REGEX = "[0-9]{7}[0-9]{2}-[0-9]{2}-[0-9]{2}$"
val DATE_PATTERN: Pattern = Pattern.compile(DATE_REGEX, Pattern.CASE_INSENSITIVE)
//private const val LOTTERY_REGEX = "^[A-Z].[0-9]{12}\\+?[0-9]{1,2}x?[0-9]+$"
private const val LOTTERY_REGEX = "^[A-Z].[0-9]{12}"
val LOTTERY_PATTERN: Pattern = Pattern.compile(LOTTERY_REGEX, Pattern.CASE_INSENSITIVE)

private const val SELL_TIME_REGEX = "^[0-9]{2}-[0-9]{2}-[0-9]{2}[0-9]{2}:[0-9]{2}:[0-9]{2}$"
val SELL_TIME_PATTERN: Pattern = Pattern.compile(SELL_TIME_REGEX, Pattern.CASE_INSENSITIVE)

suspend fun Context.initAccessTokenLicenseFile() = suspendCoroutine<Boolean> {
    val logger = AnkoLogger<MainViewModule>()
    OCR.getInstance(this).initAccessToken(object : OnResultListener<AccessToken> {
        override fun onResult(accessToken: AccessToken) {
            val token = accessToken.accessToken
            logger.info { "initAccessTokenLicenseFile: $token" }
            it.resume(true)
        }

        override fun onError(error: OCRError) {
            error.printStackTrace()
            logger.warn { "initAccessTokenLicenseFile: $error" }
            it.resume(false)
        }
    }, OCR_LICENSE, this)
}

suspend fun Context.recognizeAccurateBasic(path: String) = suspendCoroutine<GeneralResult> {
    val logger = AnkoLogger<MainViewModule>()
    val param = GeneralParams().apply {
        setDetectDirection(true)
        setVertexesLocation(true)
        setRecognizeGranularity(GeneralParams.GRANULARITY_SMALL)
        imageFile = File(path)
    }
    OCR.getInstance(this)
        .recognizeAccurateBasic(param, object : OnResultListener<GeneralResult> {
            override fun onResult(result: GeneralResult) {
                logger.info { "recognizeAccurateBasic:${result.jsonRes}" }
                it.resume(result)
            }

            override fun onError(error: OCRError) {
                logger.warn { "recognizeAccurateBasic: $error" }
                it.resumeWithException(error)
            }
        })
}

suspend fun GeneralResult.parseResult(path: String, targetDir: String) = withContext(Dispatchers.IO) {
    val logger = AnkoLogger<MainViewModule>()

    var lotteryNo = ""
    var openDate = ""
    var sellDate = ""
    var cost = ""
    val list = ArrayList<List<String>>()

    wordList.forEach {
        var content = it.words.replace(" ".toRegex(), "")
        val lotteryMatcher = LOTTERY_PATTERN.matcher(content)
        val openTimeMatcher = DATE_PATTERN.matcher(content)
        val sellTimeMatcher = SELL_TIME_PATTERN.matcher(content)
        when {
            lotteryMatcher.find() -> {
                logger.info { "LOTTERY_PATTERN $content" }
                content = content.replace("\\+".toRegex(), "")
                    .toUpperCase(Locale.getDefault())
                    .replace("X".toRegex(), "")
                val count =
                    if (content.length > 16) content.substring(16, content.length) else "1"
                val ballList = ArrayList<String>().apply {
                    add(content.substring(0, 2))
                    add(content.substring(2, 4))
                    add(content.substring(4, 6))
                    add(content.substring(6, 8))
                    add(content.substring(8, 10))
                    add(content.substring(10, 12))
                    add(content.substring(12, 14))
                    add(content.substring(14, 16))
                    add(count)
                }

                logger.info { "一组球: $ballList" }
                list.add(ballList)
            }
            openTimeMatcher.find() -> {
                lotteryNo = content.substring(6, 11)
                openDate = content.substring(11, content.length)
                logger.info { "开奖期: $lotteryNo $openDate" }
            }
            sellTimeMatcher.find() -> {
                sellDate = "${content.substring(0, 8)} ${content.substring(8, content.length)}"
                logger.info { "销售期: $sellDate" }
            }
            content.startsWith("￥:") -> {
                cost = content.replace("￥:".toRegex(), "")
                logger.info { "¥: $cost" }
            }
        }
    }
    val target = File(File(targetDir, "lottery").also { it.mkdirs() }, "${lotteryNo}_$sellDate.jpg")
    File(path).copyTo(target, true)

    OcrResult(lotteryNo, openDate, sellDate, cost, list, target.absolutePath)
}
